import utils.Model_Process as Model_Process
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import warnings

from utils.Model_Process import save_model


#
def insert_user_csv(new_data, filepath):
    """
    将新数据添加到CSV文件中。
    :param new_data: 要添加的新数据，格式为字典，键为列名，值为数据列表。
    :param filepath: CSV文件的路径，定义为data
    """
    # 读取现有的CSV文件
    try:
        df = pd.read_csv(filepath)
    except FileNotFoundError:
        # 如果文件不存在，创建一个空的DataFrame
        print("文件不存在，请查找资源")

    # 将新数据转换为DataFrame
    new_df = pd.DataFrame([new_data])

    # 将新数据追加到现有DataFrame
    df = pd.concat([df, new_df], ignore_index=True)

    # 将更新后的DataFrame保存回CSV文件
    df.to_csv(filepath, index=False)
    print(f"数据已添加")


def draw(method):
    # 加载数据集
    dataset = pd.read_csv('data/user/original_data.csv')

    # 特征选择
    X = dataset.iloc[:, [3, 4]].values

    if method == "Default":
        # 加载模型
        kmeans_model = Model_Process.load_model('models/user/Mall_Customers_KMeans_Clustering.pkl')
        y_kmeans = kmeans_model.fit_predict(X)

        # 新数据点
        new_data = pd.read_csv('data/user/new_data.csv')
        new_data_point = new_data.iloc[:, 2:4].values  # 假设收入和消费得分在第3列和第4列

        # 绘制所有簇
        plt.figure(figsize=(10, 6))
        plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置字体为黑体
        plt.rcParams["axes.unicode_minus"] = False  # 解决负号'-'显示为方块的问题
        plt.scatter(X[y_kmeans == 0, 0], X[y_kmeans == 0, 1], s=100, c='red', label='适中')
        plt.scatter(X[y_kmeans == 1, 0], X[y_kmeans == 1, 1], s=100, c='blue', label='高风险，高收益')
        plt.scatter(X[y_kmeans == 2, 0], X[y_kmeans == 2, 1], s=100, c='green', label='低风险，高收益')
        plt.scatter(X[y_kmeans == 3, 0], X[y_kmeans == 3, 1], s=100, c='cyan', label='低风险，低收益')
        plt.scatter(X[y_kmeans == 4, 0], X[y_kmeans == 4, 1], s=100, c='magenta', label='高风险，低收益')
        plt.scatter(kmeans_model.cluster_centers_[:, 0], kmeans_model.cluster_centers_[:, 1], s=100, c='yellow',
                    label='中心点')

        # 绘制新数据点
        plt.scatter(new_data_point[:, 0], new_data_point[:, 1], s=100, c='black', label='新数据点')

        # 设置图表标题和标签
        plt.title('订单乙方聚类分析')
        plt.xlabel('历史收益（万）')
        plt.ylabel('交易风险值 (0-100%)')
        plt.legend()

        # 保存图表
        plt.savefig("static/images/user/Mall_Customers_KMeans_Clustering_With_New_Data.png")

    if method != "Default":
        clustering()


def clustering():
    warnings.filterwarnings("ignore")
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 或者你可以选择其他支持中文的字体
    plt.rcParams['axes.unicode_minus'] = False  # 解决负号'-'显示为方块的问题

    mall_data = pd.read_csv('data/user/original_data.csv')

    # Kmeans聚类方法
    from sklearn.cluster import KMeans

    X_numerics = mall_data[
        ['Age', 'Annual Income (k$)', 'Spending Score (1-100)']]  # subset with numeric variables only

    from yellowbrick.cluster import KElbowVisualizer

    model = KMeans(random_state=1)
    visualizer = KElbowVisualizer(model, k=(2, 10), metric='silhouette')
    visualizer.fit(X_numerics)

    KM_5_clusters = KMeans(n_clusters=5, init='k-means++').fit(X_numerics)  # initialise and fit K-Means model
    save_model(KM_5_clusters, 'models/user/Mall_Customers_Clustering_KMeans.pkl')

    KM5_clustered = X_numerics.copy()
    KM5_clustered['Cluster'] = KM_5_clusters.labels_

    fig1, axes = plt.subplots(1, 2, figsize=(12, 5))

    # 绘制散点图
    sns.scatterplot(x='Annual Income (k$)', y='Spending Score (1-100)', data=KM5_clustered,
                    hue='Cluster', ax=axes[0], palette='Set1', legend='full')
    sns.scatterplot(x='Age', y='Spending Score (1-100)', data=KM5_clustered,
                    hue='Cluster', palette='Set1', ax=axes[1], legend='full')

    axes[0].set_xlabel('Annual Profit (W)', fontsize=12)  # 设置横坐标名称
    axes[0].set_ylabel('Risk Value (0-100%)', fontsize=12)  # 设置纵坐标名称
    axes[1].set_xlabel('Years Established', fontsize=12)  # 设置横坐标名称
    axes[1].set_ylabel('Risk Value (0-100%)', fontsize=12)  # 设置纵坐标名称

    # 在散点图中添加聚类中心点
    axes[0].scatter(KM_5_clusters.cluster_centers_[:, 1], KM_5_clusters.cluster_centers_[:, 2],
                    marker='s', s=40, c="blue")
    axes[1].scatter(KM_5_clusters.cluster_centers_[:, 0], KM_5_clusters.cluster_centers_[:, 2],
                    marker='s', s=40, c="blue")

    # 保存图形
    plt.savefig("static/images/user/Mall_Customers_Clustering_KMeans.png")
    print("K-Means finished")

    # DBSCAN聚类
    from sklearn.cluster import DBSCAN

    from itertools import product

    eps_values = np.arange(8, 12.75, 0.25)  # eps values to be investigated
    min_samples = np.arange(3, 10)  # min_samples values to be investigated

    DBSCAN_params = list(product(eps_values, min_samples))

    from sklearn.metrics import silhouette_score

    no_of_clusters = []
    sil_score = []

    for p in DBSCAN_params:
        DBS_clustering = DBSCAN(eps=p[0], min_samples=p[1]).fit(X_numerics)
        no_of_clusters.append(len(np.unique(DBS_clustering.labels_)))
        sil_score.append(silhouette_score(X_numerics, DBS_clustering.labels_))

    DBS_clustering = DBSCAN(eps=12.5, min_samples=4).fit(X_numerics)
    save_model(DBS_clustering, 'models/user/Mall_Customers_Clustering_DBSCAN.pkl')

    DBSCAN_clustered = X_numerics.copy()
    DBSCAN_clustered['Cluster'] = DBS_clustering.labels_  # append labels to points

    outliers = DBSCAN_clustered[DBSCAN_clustered['Cluster'] == -1]

    fig2, axes = plt.subplots(1, 2, figsize=(12, 5))

    # 绘制非异常点
    sns.scatterplot(x='Annual Income (k$)', y='Spending Score (1-100)',
                    data=DBSCAN_clustered[DBSCAN_clustered['Cluster'] != -1],
                    hue='Cluster', ax=axes[0], palette='Set1', legend='full', s=45)

    sns.scatterplot(x='Age', y='Spending Score (1-100)',
                    data=DBSCAN_clustered[DBSCAN_clustered['Cluster'] != -1],
                    hue='Cluster', palette='Set1', ax=axes[1], legend='full', s=45)

    axes[0].set_xlabel('Annual Profit (W)', fontsize=12)  # 设置横坐标名称
    axes[0].set_ylabel('Risk Value (0-100%)', fontsize=12)  # 设置纵坐标名称
    axes[1].set_xlabel('Years Established', fontsize=12)  # 设置横坐标名称
    axes[1].set_ylabel('Risk Value (0-100%)', fontsize=12)  # 设置纵坐标名称

    # 绘制异常点
    axes[0].scatter(outliers['Annual Income (k$)'], outliers['Spending Score (1-100)'], s=5, label='outliers', c="k")
    axes[1].scatter(outliers['Age'], outliers['Spending Score (1-100)'], s=5, label='outliers', c="k")
    axes[0].legend()
    axes[1].legend()

    # 调整图例文字大小
    plt.setp(axes[0].get_legend().get_texts(), fontsize='10')  # 设置图例字体大小
    plt.setp(axes[1].get_legend().get_texts(), fontsize='10')

    # 保存图形
    plt.savefig("static/images/user/Mall_Customers_Clustering_DBSCAN.png")
    print("DBSCAN finished")

    from sklearn.cluster import AffinityPropagation

    no_of_clusters = []
    preferences = range(-20000, -5000, 100)  # arbitraty chosen range
    af_sil_score = []  # silouette scores

    for p in preferences:
        AF = AffinityPropagation(preference=p, max_iter=200).fit(X_numerics)
        no_of_clusters.append((len(np.unique(AF.labels_))))
        af_sil_score.append(silhouette_score(X_numerics, AF.labels_))

    af_results = pd.DataFrame([preferences, no_of_clusters, af_sil_score],
                              index=['preference', 'clusters', 'sil_score']).T
    af_results.sort_values(by='sil_score', ascending=False).head()  # display only 5 best scores

    AF = AffinityPropagation(preference=-11800).fit(X_numerics)
    save_model(AF, 'models/user/Mall_Customers_Clustering_AF.pkl')

    AF_clustered = X_numerics.copy()
    AF_clustered['Cluster'] = AF.labels_  # append labels to points

    fig3, (ax_af) = plt.subplots(1, 2, figsize=(12, 5))

    scat_1 = sns.scatterplot(x='Annual Income (k$)', y='Spending Score (1-100)',
                             data=AF_clustered[AF_clustered['Cluster'] != -1],
                             hue='Cluster', ax=ax_af[0], palette='Set1', legend='full')

    sns.scatterplot(x='Age', y='Spending Score (1-100)', data=AF_clustered[AF_clustered['Cluster'] != -1],
                    hue='Cluster', palette='Set1', ax=ax_af[1], legend='full')

    ax_af[0].set_xlabel('Annual Profit (W)', fontsize=12)  # 设置横坐标名称
    ax_af[0].set_ylabel('Risk Value (0-100%)', fontsize=12)  # 设置纵坐标名称
    ax_af[1].set_xlabel('Years Established', fontsize=12)  # 设置横坐标名称
    ax_af[1].set_ylabel('Risk Value (0-100%)', fontsize=12)  # 设置纵坐标名称

    plt.setp(ax_af[0].get_legend().get_texts(), fontsize='10')
    plt.setp(ax_af[1].get_legend().get_texts(), fontsize='10')
    plt.savefig("static/images/user/Mall_Customers_Clustering_AP.png")